/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package aic.client;

import aic.beans.Address;
import aic.beans.Customer;
import aic.beans.Item;
import aic.beans.Order;
import aic.misc.DebugPrint;
import aic.rest.RestWrapperService;
import aic.security.ClientPasswordCallbackHandler;
import aic.ws.BankingService;
import aic.ws.CreateDataService;
import aic.ws.MailService;
import aic.ws.OrderManagementService;
import aic.ws.SMSService;


import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.Response;
import javax.xml.namespace.QName;


import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.soap.SOAPFaultException;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;

public final class Main {

//    private static final QName SERVICE_NAME = new QName("http://infosys.tuwien.ac.at/ait09/ass1/dto/notification", "NotificationService");
//    private static final QName PORT_NAME = new QName("http://infosys.tuwien.ac.at/ait09/ass1/dto/notification", "NotificationPT");
//    private static final URL WSDL_URL = new URL("http://localhost:9000/SMSService?wsdl");
    public static void main(String args[]) throws SOAPFaultException {

        boolean useSecurity = true;

        System.out.println("Creating Client:");
        try {
//            URL WSDL_URL = new URL("http://localhost:9000/SMSService?wsdl");

            //Create dataService
//            Service cds = Service.create(new URL("http://localhost:9000/CreateDataService?wsdl"), new QName("http://infosys.tuwien.ac.at/ait09/ass1/dto/createData", "CreateDataService"));
//            cds.addPort(new QName("http://infosys.tuwien.ac.at/ait09/ass1/dto/createData", "CreateDataPT"), SOAPBinding.SOAP11HTTP_BINDING, "http://localhost:9000/CreateDataService");
            Service cds = Service.create(new URL("http://localhost:8081/CreateDataService?wsdl"), new QName("http://ws.aic/", "CreateDataService"));
            cds.addPort(new QName("http://ws.aic/", "CreateDataPT"), SOAPBinding.SOAP11HTTP_BINDING, "http://localhost:8081/CreateDataService");
            CreateDataService createDataService = cds.getPort(CreateDataService.class);
            DebugPrint.println("CreateDataService created successfully");

            Address address = createDataService.create_address("Street One", "Vienna", 1, 14, "1190");
            Customer customer = createDataService.create_customer("user1", address);

//            Create smsService
            Service sms = Service.create(new URL("http://localhost:8088/SMSService?wsdl"), new QName("http://ws.aic/", "NotificationService"));
            sms.addPort(new QName("http://ws.aic/", "NotificationPT"), SOAPBinding.SOAP11HTTP_BINDING, "http://localhost:8088/SMSService");
            SMSService smsService = sms.getPort(SMSService.class);
            DebugPrint.println("SMSService created successfully");

            DebugPrint.println("Sending a valid SMSService massage..");
            smsService.notify_customer(customer, "Hey, Ho. This is the ultimative message! Over and out!");
            DebugPrint.println("Sending an invalid SMSService massage (User doesn't exist)..");
            Customer invalidCustomer = new Customer();
            invalidCustomer.setName("Invalid User");
            invalidCustomer.setAddress(address);
            try {
                smsService.notify_customer(invalidCustomer, "Hey, Ho. This is the ultimative message! Over and out!");
            } catch (SOAPFaultException e) {
                DebugPrint.println(e.toString());
            }
            DebugPrint.println("Sending an invalid SMSService massage (Message too long)..");
            try {
                smsService.notify_customer(invalidCustomer, "Hey, Ho. This is the ultimative message witch is tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long! Over and out!");
            } catch (SOAPFaultException e) {
                DebugPrint.println(e.toString());
            }

            //Create mailService
            Service ms = Service.create(new URL("http://localhost:8089/MailService?wsdl"), new QName("http://ws.aic/", "NotificationService"));
            ms.addPort(new QName("http://ws.aic/", "NotificationPT"), SOAPBinding.SOAP11HTTP_BINDING, "http://localhost:8089/MailService");
            MailService mailService = ms.getPort(MailService.class);
            DebugPrint.println("MailService created successfully");

            DebugPrint.println("Sending a valid MailService massage..");
            mailService.notify_customer(customer, "Hey, Ho. This is the ultimative Message! Over and Out!");
            DebugPrint.println("Sending an invalid MailService massage (User doesn't exist)..");
            try {
                mailService.notify_customer(invalidCustomer, "Hey, Ho. This is the ultimative message! Over and out!");
            } catch (SOAPFaultException e) {
                DebugPrint.println(e.toString());
            }


            //Create orderManagementService
            Service oms = Service.create(new URL("http://localhost:8083/OrderManagementService?wsdl"), new QName("http://ws.aic/", "OrderManagementService"));
            oms.addPort(new QName("http://ws.aic/", "OrderManagementPT"), SOAPBinding.SOAP11HTTP_BINDING, "http://localhost:8083/OrderManagementService");
            OrderManagementService orderManagementService = oms.getPort(OrderManagementService.class);
            DebugPrint.println("OrderManagementService created successfully");


            orderManagementService.insert_test_data();
            // check availability
            Item itemAvailable = new Item(4, "Pen", 9.90);
            DebugPrint.println("Checking the availability of an Item that is available.. (" + itemAvailable + ")");
            DebugPrint.println("..return value: " + orderManagementService.check_availability(itemAvailable));

            Item itemUnavailable = new Item(13, "Fountain-Pen", 14.90);
            DebugPrint.println("Checking the availability of an Item that is not available.. (" + itemUnavailable + ")");
            DebugPrint.println("..return value: " + orderManagementService.check_availability(itemUnavailable));

            Item itemNotExisting = new Item(14, "Non-existing Item", 12.34);
            DebugPrint.println("Checking the availability of an Item that does not exist.. (" + itemNotExisting + ")");
            try {
                DebugPrint.println("..return value: " + orderManagementService.check_availability(itemNotExisting));
            } catch (Exception e) {
                DebugPrint.println(e.toString());
            }

            // order items
            Item itemAvailable2 = new Item(3, "Fountain-Pen", 14.90);
            Item itemAvailable3 = new Item(2, "Ballpen", 2.99);
            Item[] itemsToOrder = {itemAvailable, itemAvailable2, itemAvailable3};
            DebugPrint.println("Place a valid order..");
            Order myOrder = orderManagementService.place_order(itemsToOrder, customer);
            DebugPrint.println("..done");

            Item[] itemsToOrderInvalid = {itemAvailable, itemAvailable2, itemUnavailable};
            DebugPrint.println("Place an invalid order (too much quantity)..");
            try {
                orderManagementService.place_order(itemsToOrderInvalid, customer);
            } catch (Exception e) {
                DebugPrint.println(e.toString());
            }
            DebugPrint.println("..done");

            DebugPrint.println("Checking whether the ordered items are already shipped.. (will return false)");
            DebugPrint.println("..return value: " + orderManagementService.is_finished(myOrder));

            DebugPrint.println("Waiting for 7.5 seconds..");
            Thread.sleep(7500);

            DebugPrint.println("Checking whether the ordered items are already shipped.. (could return either true or false)");
            DebugPrint.println("..return value: " + orderManagementService.is_finished(myOrder));

            DebugPrint.println("Waiting for 3 seconds..");
            Thread.sleep(3000);

            DebugPrint.println("Checking whether the ordered items are already shipped.. (will return true)");
            DebugPrint.println("..return value: " + orderManagementService.is_finished(myOrder));


            //Create bankingService
            Service bs = Service.create(new URL("http://localhost:8084/BankingService?wsdl"), new QName("http://ws.aic/", "BankingService"));
            bs.addPort(new QName("http://ws.aic/", "BankingPT"), SOAPBinding.SOAP11HTTP_BINDING, "http://localhost:8084/BankingService");
            BankingService bankingService = bs.getPort(BankingService.class);
            DebugPrint.println("BankingService created successfully");


            if (useSecurity) {
                DebugPrint.println("Doing the security stuff..");
                org.apache.cxf.endpoint.Client client = org.apache.cxf.frontend.ClientProxy.getClient(bankingService); // TODO maybe use bs instead of bankingService
                org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();

                DebugPrint.println("Creating the inProps..");
                Map<String, Object> inProps = new HashMap<String, Object>();

                WSS4JInInterceptor wssIn = new WSS4JInInterceptor(inProps);
                cxfEndpoint.getInInterceptors().add(wssIn);
//            cxfEndpoint.getInInterceptors().add(new SAAJInInterceptor()); // 2.0.x only; not needed in 2.1+

                DebugPrint.println("Creating the outProps..");
                Map<String, Object> outProps = new HashMap<String, Object>();

                DebugPrint.println("Adding the Interceptor..");
                WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
                cxfEndpoint.getOutInterceptors().add(wssOut);
//            cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor()); // 2.0.x only; not needed in 2.1+

                DebugPrint.println("Putting something into the outProps..");
                outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
                // Specify our username
                outProps.put(WSHandlerConstants.USER, "joe");
                // Password type : plain text
                outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
                // for hashed password use:
                //properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
                // Callback used to retrieve password for given user.
                outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallbackHandler.class.getName());

                try {
                    DebugPrint.println("Charging the credit card..");
                    bankingService.charge_credit_card(customer, 123);
                } catch (Exception e) {
                    DebugPrint.println(e.toString());
                }

                outProps.put(WSHandlerConstants.USER, "moe");

                try {
                    DebugPrint.println("Charging the credit card.. (wrong username)");
                    bankingService.charge_credit_card(customer, 123);
                } catch (Exception e) {
                    DebugPrint.println(e.toString());
                }

            } else {
                DebugPrint.println("Charging the credit card.. ");
                bankingService.charge_credit_card(customer, 123);
            }


            DebugPrint.println("Checking RESTful Service :: retrieveCustomer id=Customer1");
            WebClient webClient = WebClient.create("http://localhost:8085/");

            Customer restCustomer = webClient.path("/CustomerManagementService/retrieveCustomer/Customer1").accept("application/xml").get(Customer.class);
            DebugPrint.println(restCustomer.toString());

            //REST createCustomer
            DebugPrint.println("Checking RESTful Service :: createCustomer");
            Customer newRestCustomer = new Customer();
            newRestCustomer.setName("Invalid User");
            newRestCustomer.setAddress(address);

            WebClient webClient2 = WebClient.create("http://localhost:8085/");
            Response response = webClient2.path("/CustomerManagementService/createCustomer/").type("application/xml").accept("application/xml").post(newRestCustomer);
            if(response.getStatus() == Response.Status.OK.getStatusCode())
                DebugPrint.println("Customer createte with REST: OK");
            else if(response.getStatus() == Response.Status.FORBIDDEN.getStatusCode())
                DebugPrint.println("Customer createte with REST: FORBIDDEN (Customer was null)");
            else if(response.getStatus() == Response.Status.CONFLICT.getStatusCode())
                DebugPrint.println("Customer createte with REST: CONFLICT (Exception while adding customer to customerList)");

            //InputStream is = (InputStream)response.getEntity();

            //REST updateCustomer
            DebugPrint.println("Checking RESTful Service :: updateCustomer");
            newRestCustomer.setName("Updated Customer");
            WebClient webClient3 = WebClient.create("http://localhost:8085/");
            response = webClient3.path("/CustomerManagementService/updateCustomer/").type("application/xml").accept("application/xml").put(newRestCustomer);
            if(response.getStatus() == Response.Status.OK.getStatusCode())
                DebugPrint.println("Customer updated with REST: OK");
            else if(response.getStatus() == Response.Status.FORBIDDEN.getStatusCode())
                DebugPrint.println("Customer updated with REST: FORBIDDEN (Customer was null)");
            else if(response.getStatus() == Response.Status.CONFLICT.getStatusCode())
                DebugPrint.println("Customer updated with REST: CONFLICT (Exception while adding customer to customerList)");

            //REST deleteCustomer
            DebugPrint.println("Checking RESTful Service :: deleteCustomer id=Customer4");
            WebClient webClient4 = WebClient.create("http://localhost:8085/");
            response = webClient4.path("/CustomerManagementService/deleteCustomer/Customer4").accept("application/xml").delete();
            if(response.getStatus() == Response.Status.OK.getStatusCode())
                DebugPrint.println("Customer delted with REST: OK");
            else if(response.getStatus() == Response.Status.FORBIDDEN.getStatusCode())
                DebugPrint.println("Customer delted with REST: FORBIDDEN (Customer was null)");

            //REST Wrapper
            DebugPrint.println("Checking REST-Wrapper Service :: retrieveCustomer id=Customer1");
            Service rws = Service.create(new URL("http://localhost:8086/RestWrapperService?wsdl"), new QName("http://infosys.tuwien.ac.at/ait09/ass1/dto/restWrapper", "RestWrapperService"));
            rws.addPort(new QName("http://infosys.tuwien.ac.at/ait09/ass1/dto/restWrapper", "RestWrapperPT"), SOAPBinding.SOAP11HTTP_BINDING, "http://localhost:8086/RestWrapperService");
            RestWrapperService restWrapperService = rws.getPort(RestWrapperService.class);
            DebugPrint.println("RestWrapperService created successfully");

            //REST Wrapper retrieve Customer
            DebugPrint.println("REST-Wrapper Service :: retrieveCustomer customer " + restWrapperService.retrieveCustomer("Customer1").toString() + " done!");

            //REST Wrapper create Customer
            DebugPrint.println("REST-Wrapper Service :: createCustomer customer :: " + restWrapperService.createCustomer(newRestCustomer) + " :: done!");

            //REST Wrapper create Customer
            newRestCustomer.setName("Wrapper Set Name Customer");
            DebugPrint.println("REST-Wrapper Service :: createCustomer customer :: " + restWrapperService.updateCustomer(newRestCustomer) + " :: done!");

            //REST Wrapper delete Customer
            restCustomer.setName("Wrapper Set Name Customer");
            DebugPrint.println("REST-Wrapper Service :: createCustomer customer :: " + restWrapperService.deleteCustomer("Customer4") + " :: done!");

        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
        DebugPrint.println("Client created successfully");
    }
}